'use strict';
const extend = require('extend');
const logger = require('log4js').getLogger("sys");

const CommonService = require("../../service/util/dbService");
const TagService = require("./TagService");
const TagTypeService = require("./TagTypeService");
const Model = require("../../module/officialAccount/CustomerModel");
const WechatUtil = require('../../module/util/WechatUtil');
const config = require("../../config/config");

const defaultParams = {
    model : Model,
    basePath: '/customer',
};

class ModuleService extends CommonService{
    constructor(param){
        super(param);
        this.opts = extend(true, {}, this.opts, defaultParams, param);
        this._name = "CustomerService";
    }

    /**
     * 批量导入
     * @param customers
     * @param officialAccount
     * @returns {Promise}
     */
    exportIn(curUser, customers, officialAccount){
        const thisService = this;
        const superFindOne = super.findOne;
        const superSave = super.save;
        let count1 = 0, count2 = customers.length, exportInResult = [], promise;

        promise = new Promise(function (resolve, reject) {
            customers.forEach(function (customer) {
                superFindOne.call(thisService, curUser, {openid : customer.openid}).then(function (originalCustomer) {
                    if(originalCustomer){
                        thisService
                            .updateTagWithTypeById(curUser, originalCustomer._id, customer, officialAccount)
                            .then(function (result) {
                                delete customer.tags;
                                thisService.updateById(curUser, originalCustomer._id, customer).then(_result => {
                                    callback(_result);
                                });
                            })
                    }else{
                        customer.officialAccount = officialAccount.opts._id;
                        superSave.call(thisService, curUser, customer).then(function (result) {
                            thisService
                                .updateTagToWechat(curUser, customer.openid, [], customer.tags, officialAccount)
                                .then(function (wechatResult) {
                                    callback({saveResult : result, updateToWechatResult: wechatResult});
                                },function (val) {
                                    reject({});
                                });
                        })
                    }
                })
            });
            function callback(result) {
                exportInResult.push(result);
                count1++;
                if(count1 == count2){
                    resolve(exportInResult);
                }
            }
        });
        return promise;
    }

    /**
     * 根据id更新标签
     * @param id
     * @param data
     * @param officialAccount
     * @returns {Promise}
     */
    updateTagById(curUser, id, data, officialAccount){
        const thisService = this;
        const superFindById = super.findById;
        const superUpdateById = super.updateById;

        return new Promise(function (resolve, reject) {
            superFindById.call(thisService, curUser, id, "").then(function (customer) {
                thisService
                    .updateTagToWechat(curUser, customer.openid, customer.tags, data.tags, officialAccount)
                    .then(function (result) {
                        superUpdateById.call(thisService, curUser, id, data).then(function (result) {
                            resolve(result);
                        }, function (err) {
                            reject(err);
                        })
                    },function (val) {
                        reject({});
                    });
            });
        });
    }

    /**
     * 根据id更新标签,考虑标签类别
     * @param id
     * @param data {tags:[tag._id], force:Boolean}
     * @param officialAccount
     * @returns {Promise}
     */
    updateTagWithTypeById(curUser, id, data, officialAccount){
        let i;

        return new Promise((resolve, reject) => {
            TagService.find(curUser, {_id:{'$in':data.tags}}).then(tags => {
                let tagGroup = ',', tagTypeCode, errorFlag = false;
                tags.some(t => {
                    tagTypeCode = t.type || '__default_____';
                    if(new RegExp(`,${tagTypeCode},`).test(tagGroup)){
                        errorFlag = true;
                        return true;
                    }else{
                        tagGroup += tagTypeCode + ',';
                    }
                });
                if(errorFlag){
                    reject({message:'同一标签类型只能设置一个标签'});
                }else{
                    this.findById(curUser, id, 'tags').then(customer => {
                        let addTagList = [], removeTagList = [], _count = 0;
                        let _cb = () => {
                            if(_count == customer.tags.length){
                                if(addTagList.length == 0 && removeTagList == 0){
                                    resolve();
                                }else{
                                    //在微信官方更新用户标签
                                    this.addOrRemoveTagToWechat(curUser, customer.openid, officialAccount, {
                                        addTagList:addTagList,
                                        removeTagList:removeTagList
                                    }).then(updateResult => {
                                        let addTagIds = [], count = 0;
                                        addTagList.forEach(t => addTagIds.push(t._id));

                                        let cb = () => {
                                            count++;
                                            if(count == removeTagList.length + 1){
                                                resolve();
                                            }
                                        };

                                        if(addTagIds.length > 0){
                                            this.updateById(curUser, id, {'$push':{'tags':{'$each': addTagIds}}}).then(
                                                data => cb(data),
                                                err => cb(err)
                                            );
                                        }else{
                                            cb();
                                        }
                                        removeTagList.forEach(t => {
                                            this.updateById(curUser, id, {'$pull':{'tags':t._id}}).then(
                                                data => cb(data),
                                                err => cb(err)
                                            );
                                        })

                                    });
                                }
                            }
                        };

                        //计算出需要添加的标签和需要删除的标签
                        tags.forEach(t => {
                            let typeCode = t.type || '__default_____';
                            let hasFlag = false;

                            for(i = 0; i < customer.tags.length;){
                                if(customer.tags[i]._id == t._id){
                                    customer.tags.splice(i, 1);
                                    hasFlag = true;
                                    break;
                                }else{
                                    i++;
                                }
                            }

                            if(!hasFlag){
                                addTagList.push(t);
                                for(i = 0; i < customer.tags.length;){
                                    if(customer.tags[i].type == typeCode || (typeCode == '__default_____' && !customer.tags[i].type)){
                                        removeTagList = removeTagList.concat(customer.tags.splice(i, 1));
                                    }else{
                                        i++;
                                    }
                                }
                            }
                        });
                        if(data.force && customer.tags.length > 0){
                            customer.tags.forEach(t => {
                                removeTagList.push(t);
                                _count++;
                                if(t.type){
                                    TagTypeService.findById(curUser, t.type, 'defaultTag').then(tagType => {
                                        addTagList.push(tagType.defaultTag);
                                        _cb();
                                    })
                                }else{
                                    _cb();
                                }
                            });
                        }else{
                            _count = customer.tags.length;
                            _cb();
                        }
                    })
                }
            }, err => reject(err));
        });
    }

    /**
     * 同步至微信公众号
     * @param openid
     * @param originalTags
     * @param newTags
     * @param officialAccount
     * @returns {Promise}
     */
    updateTagToWechat(curUser, openid, originalTags, newTags, officialAccount){
        if(newTags && newTags.length>0) {
            let addTags = newTags.concat(), removeTags = originalTags.concat(),
                i, j, count1, count2 = 0, promise, updateResult = [];

            promise = new Promise(function (resolve, reject) {
                for (i = 0; i < addTags.length;) {
                    j = removeTags.findIndex(function (tagId) {
                        return tagId == addTags[i]
                    });
                    if (j >= 0) {
                        addTags.splice(i, 1);
                        removeTags.splice(j, 1);
                    } else {
                        i++;
                    }
                }
                count1 = addTags.length + removeTags.length;

                if(count1 == 0){
                    callback();
                }else{
                    TagService.find(curUser, {_id: {'$in': addTags}}).then(function (tags) {
                        if(tags.length == 0){
                            callback();
                        }else{
                            tags.forEach(function (tag) {
                                let batchData = {
                                    openid_list: [openid],
                                    tagid: tag.wechat_id
                                };
                                if(officialAccount) {
                                    officialAccount.batchTag(batchData).then(function (result) {
                                        logger.info(result);
                                        count2++;
                                        updateResult.push(result);
                                        callback();
                                    }, err => {
                                        count2++;
                                        callback();
                                    });
                                }
                            });
                        }

                    });
                    TagService.find(curUser, {_id: {'$in': removeTags}}).then(function (tags) {
                        if(tags.length == 0){
                            callback();
                        }else{
                            tags.forEach(function (tag) {
                                let unbatchData = {
                                    openid_list: [openid],
                                    tagid: tag.wechat_id
                                };
                                officialAccount.unbatchTag(unbatchData).then(function (result) {
                                    logger.info(result);
                                    count2++;
                                    updateResult.push(result);
                                    callback();
                                }, err => {
                                    count2++;
                                    callback();
                                });
                            });
                        }
                    });
                }

                function callback() {
                    if (count1 == count2) {
                        logger.info('update tag success', openid, removeTags, addTags);
                        resolve(updateResult);
                    }
                }
            });

            return promise;
        } else {
            return new Promise(function (resolve, reject) {
                resolve(originalTags);
            });
        }
    }
    /**
     *
     * @param curUser
     * @param openid
     * @param officialAccount
     * @param updateTag {addTagList:[], removeTagList:[]}
     * @return {*}
     */
    addOrRemoveTagToWechat(curUser, openid, officialAccount, updateTag = {addTagList:[], removeTagList:[]}){
        return new Promise((resolve, reject) => {
            let total = updateTag.addTagList.length + updateTag.removeTagList.length,
                count = 0, updateResult = {successResult:[], failResult:[]};
            let cb = () => {
                count++;
                if(total == count){
                    resolve(updateResult);
                }
            };

            updateTag.addTagList.forEach((tag) => {
                let batchData = {
                    openid_list: [openid],
                    tagid: tag.wechat_id
                };
                officialAccount.batchTag(batchData).then((result) => {
                    updateResult.successResult.push(result);
                    cb();
                }, err => {
                    updateResult.failResult.push(err);
                    cb();
                });
            });
            updateTag.removeTagList.forEach((tag) => {
                let unbatchData = {
                    openid_list: [openid],
                    tagid: tag.wechat_id
                };
                officialAccount.unbatchTag(unbatchData).then((result) => {
                    updateResult.successResult.push(result);
                    cb();
                }, err => {
                    updateResult.failResult.push(err);
                    cb();
                });
            });
        });
    }

    /**
     * 从官方拉取粉丝信息
     * @param officialAccount
     * @returns {Promise}
     */
    sync(curUser, officialAccount){
        const thisService = this;
        const superFind = super.find;
        const superCreate = super.create;
        let condition = {officialAccount : officialAccount.opts._id};
        return new Promise(function (resolve, reject) {
            officialAccount.getCustomerList().then(function (customers) {
                let openids = [], newCustomer = [], successCount = 0, failCount = 0;

                if(customers.errcode && customers.errcode != 0){
                    reject(customers);
                }else{
                    if(customers.total != 0){
                        openids = customers.data.openid;

                        condition.openid = {'$in': openids};
                        superFind.call(thisService, curUser, condition).then(function (hereCustomers) {
                            let i;
                            for(i = 0; i < openids.length; ){
                                let flag = hereCustomers.find(function (customer) {
                                    return customer.openid == openids[i];
                                });
                                if(flag){
                                    openids.splice(i, 1);
                                }else{
                                    newCustomer.push({
                                        openid: openids[i],
                                        officialAccount: officialAccount.opts._id,
                                    });
                                    i++;
                                }
                            }
                            if(newCustomer.length == 0){
                                resolve({successCount:successCount, failCount: failCount});
                            }else{
                                newCustomer.forEach(function (customer) {
                                    officialAccount.getCustomerInfo(customer.openid).then(function (result) {
                                        if(result == null){
                                            failCount++;
                                        }else{
                                            customer = extend(customer, result);
                                            if(result.subscribe_time){
                                                customer.focusTime = new Date(result.subscribe_time * 1000);
                                            }
                                            if(result.nickname){
                                                customer.name = result.nickname;
                                            }
                                            customer.tags = [];
                                            officialAccount.getUserTags(customer.openid).then(function (tagResult) {
                                                let createCustomers = function () {
                                                    successCount++;
                                                    logger.info('customer sync process', `${successCount + failCount}/${newCustomer.length}`);
                                                    if((successCount + failCount) == newCustomer.length){
                                                        superCreate.call(thisService, curUser, newCustomer).then(function (result) {
                                                            resolve({result: result, successCount:successCount, failCount: failCount});
                                                        }, function (err) {
                                                            reject(err);
                                                        });
                                                    }
                                                };
                                                if(tagResult.tagid_list.length == 0){
                                                    createCustomers();
                                                }else{
                                                    TagService
                                                        .find(curUser, {wechat_id:{'$in':tagResult.tagid_list}, officialAccount: officialAccount.opts._id})
                                                        .then(function (tags) {
                                                            tags.forEach(function (tag) {
                                                                customer.tags.push(tag._id);
                                                            });
                                                            createCustomers();
                                                        })
                                                }
                                            }, function (err) {
                                                failCount++;
                                            });
                                        }
                                    }, function (err) {
                                        failCount++;
                                    })
                                });
                            }

                        });
                    }else{
                        resolve({successCount:0, failCount: 0});
                    }
                }
            }, function (err) {
                reject(err);
            });
        });
    }

    /**
     *
     * @param curUser
     * @param officialAccount
     * @param condition
     * @param tag TagModel
     * @return {Promise}
     */
    batchTagWithWX(curUser, officialAccount, condition, tag){
        return new Promise((resolve, reject) => {
            //查询需要添加的粉丝
            this.find(curUser, condition, undefined, undefined, 'openid').then(customers => {
                if(customers.length == 0){
                    resolve();
                }else{
                    let openIds = [];
                    customers.forEach(c => openIds.push(c.openid));

                    let wechatData = {
                        "openid_list" : openIds.concat(),
                        "tagid" : tag.wechat_id
                    };
                    //在官方绑定标签
                    officialAccount.batchTag(wechatData).then(wxResult => {
                        //在本地绑定标签
                        this.update(curUser, condition, {'$push':{tags:tag._id}}, {multi: true}).then(
                            localResult => resolve(localResult),
                            err => reject(err)
                        )
                    }, err => reject(err))
                }
            });
        })
    }

    getAllInfo(curUser, code){
        let serverUrl = (curUser.officialAccount && curUser.officialAccount.brand && curUser.officialAccount.brand.serverUrl) || config.api.serverUrl;

        return new Promise((resolve, reject) => {
            let flag = true, count = 0, data, err;
            let cb = () => {
                count++;
                if(count == infos.length){
                    if(flag){
                        resolve(data);
                    }else{
                        reject(err);
                    }
                }
            };

            let infos = ['order','address','point','account','cast','gift'];
            infos.forEach(type => {
                global.util.request({
                    method: 'get',
                    uri: `${serverUrl}/customer/info/${type}/{code}`,
                }, {code:code}).then((body, response) => {
                    logger.info('customer', "request order success", body);
                    data[type] = body;
                    cb();
                }, (error, response) => {
                    logger.error('customer', "request order fail", error);
                    flag = false;
                    err = error;
                    cb();
                });
            });
        });
    }
}

module.exports = new ModuleService();


